﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Qianke.Core.Common;
using Qianke.Core.Common.Models;
using System.Reflection;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Auditing;
using Volo.Abp.Validation;

namespace Qianke.Core.Saas.WebApi.SaasExtensions.SaasFilters
{
    public class SaasAsyncActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var auditingManager = context.GetRequiredService<IAuditingManager>();
            var actionMethodInfo = context.ActionDescriptor.GetMethodInfo();

            var dict = auditingManager?.Current?.Log?.ExtraProperties;
            if (dict != null)
            {
                var auditingHelper = context.GetRequiredService<IAuditingHelper>();
                if (auditingHelper.ShouldSaveAudit(context.ActionDescriptor.GetMethodInfo()))
                    dict["WriteCallApiLog"] = true;
                else
                    dict["WriteCallApiLog"] = false;
            }
            
            var result = await next();
            context.HttpContext.RequestAborted = new CancellationToken(false);
            //var controllerName = context.Controller.GetType().Name;
            //if (controllerName == "AbpApiDefinitionController")
            //    return;

            if (!actionMethodInfo.IsDefined(typeof(IgnoreFormattingReturnValueAttribute), true))
                HandResult(result, context);

            var resultValue = result.Result as ObjectResult;
            if(dict != null)
            {
                if (resultValue != null)
                    dict["ApiReturnValue"] = resultValue.Value.ToJson();
                dict["TokenInfo"] = context.GetRequiredService<SaasRequestInfo>().TokenModel.ToJson();
                dict["ApiUrl"] = $"{context.HttpContext.Request.Scheme}://{context.HttpContext.Request.Host}{context.HttpContext.Request.Path}";
            }
            //这里要更改CancellationToken对象，防止前端取消请求时，后端还在执行异步方法

        }

        private void HandResult(ActionExecutedContext result, ActionExecutingContext context)
        {
            if (result.Exception != null)
            {
                result.ExceptionHandled = true;
                if (result.Exception is AbpValidationException validationException)
                {
                    var errorArray = validationException.ValidationErrors.Select(x => $"{string.Join(",", x.MemberNames)}={x.ErrorMessage}");
                    var errorInfo = string.Join(Environment.NewLine, errorArray);
                    result.Result = new ObjectResult(new ReturnInfo("100", "参数验证失败：" + errorInfo));
                    return;
                }
                result.Result = new ObjectResult(new ReturnInfoData("500", result.Exception.Message, new { 
                    result.Exception.StackTrace,
                    InnerException = result.Exception.InnerException?.Message,
                    InnerExceptionStackTrace = result.Exception.InnerException?.StackTrace
                }));
                return;
            }
            if (result.ExceptionHandled)
            {
                result.Result = new ObjectResult(new ReturnInfo("400","未知错误，但是存在异常处理标志"));
                return;
            }

            var resultObject = result.Result as ObjectResult;
            if (resultObject != null)
            {
                if (resultObject.Value is ReturnInfo)
                    return;
                result.Result = new ObjectResult(new ReturnInfoData(resultObject.Value));
                return;
            }
            if (result.Result is EmptyResult)
            {
                result.Result = new ObjectResult(ReturnInfo.Success);
                //context.HttpContext.Response.StatusCode = 200;
                return;
            }
        }
    }
}
